/* Copyright (C) 2003, Charles Wang.
 * Author:  Charles Wang <charles@linux.net.cn>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANT; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public LIcense for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "proc-parser.h"

static const char *bstr = " \t\n";
static const char *dstr = "0123456789";

int  parse_cpuinfo(cpuinfo_struct *cpuinfo) {
    return 0;
}
void free_cpuinfo(cpuinfo_struct *cpuinfo) {
}

int  parse_meminfo(meminfo_struct *meminfo) {
    FILE *fp;
    char  lnbuf[256];
    char *c;

    if ((fp = fopen("/proc/meminfo", "r")) == NULL)
	return 1;
    if (fgets(lnbuf, sizeof(lnbuf), fp) == NULL)
	return 1;
    if (fgets(lnbuf, sizeof(lnbuf), fp) == NULL)
	return 1;
    c = lnbuf + strcspn(lnbuf, dstr);
    meminfo->total = atol(c);
    c += strspn(c, dstr); c += strcspn(c, dstr);
    meminfo->used = atol(c);
    c += strspn(c, dstr); c += strcspn(c, dstr);
    meminfo->free = atol(c);
    fclose(fp);
    return 0;
}
void free_meminfo(meminfo_struct *meminfo) {
}

int  parse_filesystems(filesystem_array *filesystems) {
    FILE *fp;
    char  lnbuf[64];
    char *c1, *c2;

    if ((fp = fopen("/proc/filesystems", "r")) == NULL)
	return 1;
    memset(filesystems, 0, sizeof(*filesystems));
    while(fgets(lnbuf, sizeof(lnbuf), fp) != NULL) {
	if (filesystems->num == 32) {
	    if (filesystems->next != NULL)  filesystems = filesystems->next;
	    else {
		if ((filesystems->next = malloc(sizeof(*filesystems))) == NULL)
		    return 1;
		filesystems = filesystems->next;
		memset(filesystems, 0, sizeof(*filesystems));
	    }
	}
	c1 = strchr(lnbuf, '\t'); c2 = strchr(lnbuf, '\n');
	filesystems->names[filesystems->num] = strndup(c1 + 1, c2 - c1 -1);
	if (c1 == lnbuf)   filesystems->devmask |= 1 << filesystems->num;
	++filesystems->num;
    }
    fclose(fp);
    return 0;
}
void free_filesystems(filesystem_array *filesystems) {
    int  i;
    while (filesystems != NULL) {
	for (i = 0; i < filesystems->num; ++i)
	    if (filesystems->names[i] != NULL)
		free(filesystems->names[i]);
	filesystems->num = 0;
	filesystems = filesystems->next;
    }
}

int  parse_ides(ide_array *ides) {
    DIR  *proc_ide;
    struct dirent *de;
    char  fnbuf[64];
    FILE *fp, *fp0;
    char  lnbuf[256];
    int   ide_ok;
    char *c;

    if ((proc_ide = opendir("/proc/ide")) == NULL)
	return 1;
    memset(ides, 0, sizeof(*ides));
    while ((de = readdir(proc_ide)) != NULL) {
	if (de->d_name[0] == 'h' && de->d_name[1] == 'd') {
	    ide_ok = 1;
	    if (ides->num == 32) {
		if (ides->next != NULL)  ides = ides->next;
		else {
		    if ((ides->next = malloc(sizeof(*ides))) == NULL)
			return 1;
		    ides = ides->next;
		    memset(ides, 0, sizeof(*ides));
		}
	    }
	    /* Get the capacity of it. */
	    ides->capacity[ides->num] = 0;
	    snprintf(fnbuf, sizeof(fnbuf), "/proc/ide/%s/capacity", de->d_name);
	    if ((fp = fopen(fnbuf, "r")) != NULL) {
		if (fgets(lnbuf, sizeof(lnbuf), fp) != NULL)
		    ides->capacity[ides->num] = atol(lnbuf);
		fclose(fp);
	    }
	    /* Get the type of it. */
	    snprintf(fnbuf, sizeof(fnbuf), "/proc/ide/%s/media", de->d_name);
	    if ((fp = fopen(fnbuf, "r")) != NULL) {
		if (fgets(lnbuf, sizeof(lnbuf), fp) != NULL) {
		    if (!strcmp(lnbuf, "disk\n")) {
			snprintf(fnbuf, sizeof(fnbuf), "/proc/ide/%s/geometry", de->d_name);
			if ((fp0 = fopen(fnbuf, "r")) != NULL) {
			    if (fgets(lnbuf, sizeof(lnbuf), fp0) != NULL
				&& fgets(lnbuf, sizeof(lnbuf), fp0) != NULL) {
				c = lnbuf + strcspn(lnbuf, dstr);
				ides->cylinders[ides->num] = atoi(c);
				c = strchr(c, '/');
				ides->heads[ides->num] = atoi(c + 1);
				c = strchr(c + 1, '/');
				ides->sectors[ides->num] = atoi(c + 1);
			    }
			    fclose(fp0);
			}
			ides->diskmask |= 1 << ides->num;
		    } else if (!strcmp(lnbuf, "cdrom\n")) {
			/* Do nothing is ok. */
		    } else
			ide_ok = 0;
		}
		fclose(fp);
	    }
	    if (ide_ok)  ides->devs[ides->num] = strdup(de->d_name);
	    ides->num += ide_ok;
	}
    }
    closedir(proc_ide);
    return 0;
}
void free_ides(ide_array *ides) {
    int  i;
    while (ides != NULL) {
	for (i = 0; i < ides->num; ++i)
	    if (ides->devs[i] != NULL)
		free(ides->devs[i]);
	ides->num = 0;
	ides->diskmask = 0;
	ides = ides->next;
    }
}

int  parse_scsis(scsi_array *scsis) {
    DIR  *proc_scsi;
    struct dirent *de;
    char  devbuf[32];

    if ((proc_scsi = opendir("/proc/scsi")) == NULL)
	return 1;
    memset(scsis, 0, sizeof(*scsis));
    while ((de = readdir(proc_scsi)) != NULL) {
	if (!strncmp(de->d_name, "usb-storage-", strlen("usb-storage-"))) {
	    if (scsis->num == 32) {
		if (scsis->next != NULL)  scsis = scsis->next;
		else {
		    if ((scsis->next = malloc(sizeof(*scsis))) == NULL)
			return 1;
		    scsis = scsis->next;
		    memset(scsis, 0, sizeof(*scsis));
		}
	    }
	    scsis->types[scsis->num] = MISCSI_USBSTORAGE;
	    snprintf(devbuf, sizeof(devbuf), "sd%c",
		     'a' + atoi(de->d_name + strlen("usb-storage-")));
	    scsis->devs[scsis->num] = strdup(devbuf);
	    ++scsis->num;
	}
    }
    closedir(proc_scsi);
    return 0;
}
void free_scsis(scsi_array *scsis) {
    int  i;
    while (scsis != NULL) {
	for (i = 0; i < scsis->num; ++i)
	    if (scsis->devs[i] != NULL)
		free(scsis->devs[i]);
	scsis->num = 0;
	scsis = scsis->next;
    }
}

int  parse_partitions(partition_array *partitions) {
    FILE *fp;
    char  lnbuf[256];
    char *c;

    if ((fp = fopen("/proc/partitions", "r")) == NULL)
	return 1;
    memset(partitions, 0, sizeof(*partitions));
    /* Skip the two title lines. */
    fgets(lnbuf, sizeof(lnbuf), fp);
    fgets(lnbuf, sizeof(lnbuf), fp);
    while (fgets(lnbuf, sizeof(lnbuf), fp) != NULL) {
	if (partitions->num == 32) {
	    if (partitions->next != NULL)  partitions = partitions->next;
	    else {
		if ((partitions->next = malloc(sizeof(*partitions))) == NULL)
		    return 1;
		partitions = partitions->next;
		memset(partitions, 0, sizeof(*partitions));
	    }
	}
	c = lnbuf + strcspn(lnbuf, dstr);
	partitions->major[partitions->num] = atoi(c);
	c += strspn(c, dstr);  c += strcspn(c, dstr);
	partitions->minor[partitions->num] = atoi(c);
	c += strspn(c, dstr);  c += strcspn(c, dstr);
	partitions->blocks[partitions->num] = atol(c);
	c += strspn(c, dstr);  c += strspn(c, bstr);
	partitions->names[partitions->num] = strndup(c, strcspn(c, bstr));
	++partitions->num;
    }
    fclose(fp);
    return 0;
}
void free_partitions(partition_array *partitions) {
    int  i;
    while (partitions != NULL) {
	for (i = 0; i < partitions->num; ++i)
	    if (partitions->names[i] != NULL)
		free(partitions->names[i]);
	partitions->num = 0;
	partitions = partitions->next;
    }
}
